﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Tea;
using Tea.Utils;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Alidns20150109;
using AlibabaCloud.SDK.Alidns20150109.Models;
using System.Linq;
using static System.Net.Mime.MediaTypeNames;
using System.Net.Http;
using System.Text.Json.Serialization;

namespace AlyDdns
{
    public class DomainNameToUpdateInfo
    {
        public string? AccessKeyId { get; set; }
        public string? AccessKeySecret { get; set; }
        /// <summary>
        /// 检测间隔,单位分钟
        /// </summary>
        public int CheckInterval { set; get; }
        public int AlivePort {  set; get; }
        public List<string> DomainNames { get; set; }=new List<string>();
    }
    public class AlyDnsService
    {
        static object _logLock = new object();
        public bool Status = false;
        public bool _toStop=false;
        void Log(string msg)
        {
            lock (_logLock)
            {
                var now = DateTime.Now;
                var logFileName = $"log-{now.Year}-{now.Month}-{now.Day}.txt";
                File.AppendAllLines(logFileName, new[] { $"{now}:{msg}" });
            }
        }
        void Log(Exception ex)
        {
            Log(ex.ToString());
        }
        string? GetLocalPublicIp()
        {
            Console.Write($"{DateTime.Now}:Get Public Ip=>");
            string? tempip;

            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Clear();
                httpClient.DefaultRequestHeaders.Add("Accept","text /html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
                httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
                httpClient.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
                httpClient.DefaultRequestHeaders.Add("Proxy-Connection", "keep-alive");
                httpClient.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
                httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61");
                var url = "http://v4.ip.zxinc.org/info.php?type=json";
                var json = httpClient.GetStringAsync(url).GetAwaiter().GetResult();
                if (json == null)
                    throw new Exception($"取本地公有IP异常:httpClient.GetStringAsync(url)返回空,url:{url}");
                var robj = JsonDocument.Parse(json);
                if (robj == null)
                    throw new Exception($"取本地公有IP异常:JsonDocument.Parse(json)返回空,,url:{url}");
                tempip = robj.RootElement.GetProperty("data").GetProperty("myip").GetString();
            }
            Console.WriteLine(tempip);
            return tempip;
        }
        Client CreateClient(string accessKeyId, string accessKeySecret)
        {   
            Config config = new Config
            {
                // 您的AccessKey ID
                AccessKeyId = accessKeyId,
                // 您的AccessKey Secret
                AccessKeySecret = accessKeySecret,
            };
            // 访问的域名
            config.Endpoint = "alidns.cn-hangzhou.aliyuncs.com";
            return new Client(config);
        }
        async void CheckDomainNameSettings(DomainNameToUpdateInfo dntuInfo)
        {
            if (dntuInfo.AccessKeyId == null)
                throw new Exception("CheckDomainNameSettings AccessKeyId is null");
            if (dntuInfo.AccessKeySecret == null)
                throw new Exception("CheckDomainNameSettings AccessKeySecret is null");
            var client = CreateClient(dntuInfo.AccessKeyId,dntuInfo.AccessKeySecret);
            foreach (var dn in dntuInfo.DomainNames)
            {
                var index = dn.IndexOf(".");
                var RR = dn.Substring(0,index);
                var domainName = dn.Remove(0, index + 1);
                var describeDomainRecordsRequest = new DescribeDomainRecordsRequest();
                describeDomainRecordsRequest.DomainName = domainName;
                var dc = client.DescribeDomainRecords(describeDomainRecordsRequest);
                var recordList = dc.Body.DomainRecords.Record;
                var record = recordList.SingleOrDefault(it => it.DomainName == domainName && it.RR == RR);
                if (record == null)
                {
                    continue;
                }
                //record.Value
                using(var httpClient=new HttpClient())
                {
                    try
                    {
                        var status = await httpClient.GetStringAsync($"http://{record.Value}:{dntuInfo.AlivePort}");
                        if (status == "1")
                        {
                            continue;
                        }
                    }
                    catch
                    {

                    }
                }
                var newIp = GetLocalPublicIp();
                if (newIp == null)
                    throw new Exception("GetLocalPublicIp() return null");
                if (record.Value == newIp)
                {
                    continue;
                }
                var updateDomainRecordRequest = new AlibabaCloud.SDK.Alidns20150109.Models.UpdateDomainRecordRequest();
                updateDomainRecordRequest.Value = newIp;
                updateDomainRecordRequest.RecordId = record.RecordId;
                updateDomainRecordRequest.RR = record.RR;
                updateDomainRecordRequest.Type = record.Type;
                var rsp = client.UpdateDomainRecord(updateDomainRecordRequest);
                Console.Write($"{DateTime.Now}:Update {domainName}=>{newIp}");
                Log($"Update Ip=>{newIp}");
            }
        }
        public void Start(string dntuJsonFile)
        {
            if (Status == true)
            {
                return;
            }
            Status = true;
            _toStop = false;
            while (!_toStop)
            {
                var checkTime = DateTime.Now;
                var checkInterval = 1;
                try
                {
                    var json = File.ReadAllText(dntuJsonFile);
                    var dntuInfo =JsonSerializer.Deserialize<DomainNameToUpdateInfo>(json);
                    if (dntuInfo == null)
                        throw new Exception($"JsonSerializer.Deserialize<DomainNameToUpdateInfo>(File.ReadAllText(dntuJsonFile)) return null,dntuJsonFile:{dntuJsonFile}");
                    checkInterval = dntuInfo.CheckInterval;
                    CheckDomainNameSettings(dntuInfo);
                }
                catch (Exception ex)
                {
                    Log(ex);
                    checkInterval = 1;
                }
                var random=new Random(DateTime.Now.Millisecond);
                var dt = random.Next(checkInterval, checkInterval + 5);
                while (!_toStop)
                {
                    Thread.Sleep(100);
                    if (DateTime.Now - checkTime < new TimeSpan(0, dt, 0))
                    {
                        continue;
                    }
                    break;
                }
            }
            Status = false;
        }
        public void Stop()
        {
            _toStop= true;
        }
    }
}
